Account Factory for Terraform (AFT)で custom_fields を活用し、カスタマイズを柔軟に行う
ちゃだいん(@chazuke4649)です。
AWS Control Tower Account Factory for Terraform (AFT) の、custom_fieldsを利用して各アカウントにパラメータを配置し、それを利用してアカウントカスタマイズを実行してみます。
AFTに関する過去の記事は以下ハッシュタグよりご確認ください。
背景
AFTを使用してAWSアカウントのカスタマイズを行う際に、AWSアカウント固有のパラメータを指定したい場合があります。例えばVPCのCIDRや、ネームタグに使用するプロジェクト名や環境名などです。これらを中央で集中管理し、各AWSアカウントでそれを呼び出す構成が良さそうです。そんな時に使用できるのが、今回紹介するAFTの custom_fields
です。
端的にいうと、リクエストリポジトリのcustom_fieldsブロックにパラメータを指定すれば、当該AWSアカウントごとのSSMパラメータストアにその値が格納されるので、それを呼び出してリソースを作成すればOKです。
情報
custom_fields
についてはGitHubのアカウントリクエストのReadmeに記載があります。
custom_fields captures custom keys and values. As a customer you may want to collect additional metadata which can be logged with the Account Request and also leveraged to trigger additional processing when vending or updating an account. This metadata can be referenced during account customizations which can determine the proper guardrails which should be deployed. For example, an account that is subject to regulatory compliance could deploy an additional config rule.
(意訳)custom_fields は、カスタムのキーと値をキャプチャします。顧客としては、追加のメタデータを収集したいと思うかもしれません。これはアカウントリクエストとともに記録され、アカウントの払い出しや更新の際に追加処理を起動するために活用されます。このメタデータは、アカウントのカスタマイズ時に参照することができ、展開されるべき適切なガードレールを決定することができます。たとえば、規制遵守の対象となるアカウントには、追加の設定ルールを導入することができます。
引用元: aft-account-request · aws-ia/terraform-aws-control_tower_account_factory
実際の使い方はGitHubのIssueにて会話されていました。詳細は以下です。
それでは早速やってみます。
やってみる
前提
前のブログと同様各AFTリポジトリは以下呼称とします。
aft-account-request
: 発行したいAWSアカウントの必要情報を入力する。アカウントファクトリーの入力画面で入力する内容と同様。(リクエストリポジトリと呼称する)aft-account-provisioning-customizations
: Step Functionsを使用して、新しいアカウントのプロビジョニングプロセスをカスタマイズし、追加の環境との統合を簡素化する(プロビジョニングリポジトリと呼称する)aft-global-customizations
: プロビジョニングされたすべてのアカウントをカスタマイズする(グローバルカスタムリポジトリと呼称する)aft-account-customizations
: プロビジョニングされた任意のアカウントをカスタマイズする(アカウントカスタムリポジトリと呼称する)
手順
今回はcustom_fields
で指定したプロジェクト名やCIDRなどを使用し、アカウントのカスタマイズでVPC周りのリソース一式を作成したいと思います。
手順は以下の流れとなります。
- リクエストリポジトリに、custom_fieldsをプッシュする
- アカウントカスタマイズリポジトリに、vpcのTerraformコードをプッシュする
- 手動でアカウントカスタマイズのStepFunctionsを実行する
1. リクエストリポジトリに、custom_fieldsをプッシュする
以前ブログで紹介のAWSアカウント発行時に作成したリクエストリポジトリの対象AWSアカウントのモジュールを修正します。主にcustom_fields
にパラメータを追加します。
module "sandbox_aft_01" { source = "./modules/aft-account-request" control_tower_parameters = { AccountEmail = "[email protected]" AccountName = "sandbox-aft-01" ManagedOrganizationalUnit = "Sandbox" SSOUserEmail = "[email protected]" SSOUserFirstName = "NOT" SSOUserLastName = "USE" } account_tags = { "AFT" = true } change_management_parameters = { change_requested_by = "chadain" change_reason = "Added custom fields" } custom_fields = { project = "sandbox01" env = "dev" cidr_vpc = "10.0.0.0/16" cidr_subnet_public_a = "10.1.1.0/24" cidr_subnet_public_c = "10.1.2.0/24" cidr_subnet_public_d = "10.1.3.0/24" cidr_subnet_private_a = "10.1.11.0/24" cidr_subnet_private_c = "10.1.12.0/24" cidr_subnet_private_d = "10.1.13.0/24" cidr_subnet_database_a = "10.1.21.0/24" cidr_subnet_database_c = "10.1.22.0/24" cidr_subnet_database_d = "10.1.23.0/24" cidr_subnet_intra_a = "10.1.31.0/24" cidr_subnet_intra_c = "10.1.32.0/24" cidr_subnet_intra_d = "10.1.33.0/24" } account_customizations_name = "sandbox" }
解説
custom_fields
に指定したのは以下となります。
- projectとして
sandbox01
を指定 - envとして
dev
を指定 - cidr_vpcとして
10.0.0.0/16
を指定 - 他サブネットの各CIDRをそれぞれ指定
また、グローバルカスタマイズ(全AWSアカウント)ではなく個別のカスタマイズを行う場合は、account_customizations_name
も指定します。今回は引き続きsandbox
とします。
その後のアクション
上記入力が完了したら、プッシュしてリモートリポジトリに追加します。
すると、AFTのパイプラインの中で、アカウントリクエストのCodePipelineが走りました。
完了すると、該当AWSアカウントにSSMパラメータが格納されました。
custom_fields
によって格納されたSSMパラメータは全て名前に/aft/account-request/cusom-fields/
が頭につきます。
次の工程でこれを呼び出します。
2. アカウントカスタマイズリポジトリに、vpcのTerraformコードをプッシュする
アカウントカスタマイズリポジトリのsandbox
フォルダの中に、以下ファイルを追加します。
VPCの作成に今回はVPCモジュールを活用します。
data "aws_ssm_parameter" "project" { name = "/aft/account-request/custom-fields/project" } data "aws_ssm_parameter" "env" { name = "/aft/account-request/custom-fields/env" } data "aws_ssm_parameter" "cidr_vpc" { name = "/aft/account-request/custom-fields/cidr_vpc" } data "aws_ssm_parameter" "cidr_subnet_public_a" { name = "/aft/account-request/custom-fields/cidr_subnet_public_a" } data "aws_ssm_parameter" "cidr_subnet_public_c" { name = "/aft/account-request/custom-fields/cidr_subnet_public_c" } data "aws_ssm_parameter" "cidr_subnet_public_d" { name = "/aft/account-request/custom-fields/cidr_subnet_public_d" } data "aws_ssm_parameter" "cidr_subnet_private_a" { name = "/aft/account-request/custom-fields/cidr_subnet_private_a" } data "aws_ssm_parameter" "cidr_subnet_private_c" { name = "/aft/account-request/custom-fields/cidr_subnet_private_c" } data "aws_ssm_parameter" "cidr_subnet_private_d" { name = "/aft/account-request/custom-fields/cidr_subnet_private_d" } data "aws_ssm_parameter" "cidr_subnet_database_a" { name = "/aft/account-request/custom-fields/cidr_subnet_database_a" } data "aws_ssm_parameter" "cidr_subnet_database_c" { name = "/aft/account-request/custom-fields/cidr_subnet_database_c" } data "aws_ssm_parameter" "cidr_subnet_database_d" { name = "/aft/account-request/custom-fields/cidr_subnet_database_d" } data "aws_ssm_parameter" "cidr_subnet_intra_a" { name = "/aft/account-request/custom-fields/cidr_subnet_intra_a" } data "aws_ssm_parameter" "cidr_subnet_intra_c" { name = "/aft/account-request/custom-fields/cidr_subnet_intra_c" } data "aws_ssm_parameter" "cidr_subnet_intra_d" { name = "/aft/account-request/custom-fields/cidr_subnet_intra_d" } locals { project = data.aws_ssm_parameter.project.value env = data.aws_ssm_parameter.env.value region = "ap-northeast-1" name = "${local.project}-${local.env}-vpc" vpc_tags = { Name = "${local.project}-${local.env}-vpc" } azs = ["${local.region}a", "${local.region}c", "${local.region}d", ] cidr = data.aws_ssm_parameter.cidr_vpc.value public_subnets = [ data.aws_ssm_parameter.cidr_subnet_public_a.value, data.aws_ssm_parameter.cidr_subnet_public_c.value, data.aws_ssm_parameter.cidr_subnet_public_d.value ] private_subnets = [ data.aws_ssm_parameter.cidr_subnet_private_a.value, data.aws_ssm_parameter.cidr_subnet_private_c.value, data.aws_ssm_parameter.cidr_subnet_private_d.value ] database_subnets = [ data.aws_ssm_parameter.cidr_subnet_database_a.value, data.aws_ssm_parameter.cidr_subnet_database_c.value, data.aws_ssm_parameter.cidr_subnet_database_d.value ] intra_subnets = [ data.aws_ssm_parameter.cidr_subnet_intra_a.value, data.aws_ssm_parameter.cidr_subnet_intra_c.value, data.aws_ssm_parameter.cidr_subnet_intra_d.value ] } module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.10.0" name = local.name cidr = local.cidr vpc_tags = local.vpc_tags azs = local.azs public_subnets = local.public_subnets private_subnets = local.private_subnets database_subnets = local.database_subnets intra_subnets = local.intra_subnets }
解説
data sourceブロック
1-15行目で データソースとして各SSMパラメータを呼び出してTerraformで使える状態にしています。
aws_ssm_parameter | Data Sources | hashicorp/aws | Terraform Registry
localsブロック
18-44行目で記入しているlocalsの使用は必須ではありませんが、moduleブロック自体の記述をシンプルにするために使用します。
localsのprojectやenv,cidrなどdata sourceブロックからローカル変数に格納します。
vpc moduleブロック
51-59行目にはvpc moduleブロックにてローカル変数を指定しています。vpc module自体の使用方法詳細は先述のドキュメントを参照ください。
こうすることによって、アカウントリポジトリのcustom_fields -> 各AWSアカウントのSSMパラメータ -> アカウントカスタマイズのTerraformコード といった流れで値を渡すことができます。
その後のアクション
上記入力が完了したら、プッシュしてリモートリポジトリに追加します。 アカウントカスタマイズの場合、プッシュした段階で既存AWSアカウントに更新処理が走ることはないので、特に他パイプライン等が発火することはありません。
3. 手動でアカウントカスタマイズのStepFunctionsを実行する
更新したカスタマイズを反映させるために、StepFuntionsステートマシンを手動で実行します。本工程の詳細はこちらをご覧ください。
{ "include": [ { "type": "accounts", "target_value": [ "123456789012"] } ] }
※AWSアカウントIDはダミーです
AFTアカウントのaft-invoke-cusomizations
ステートマシンに対し、これをinputに入れて、実行します。
すると、ステートマシンによって指定した指定したAWSアカウントのカスタマイズのCodePipelineがキックされました。
パイプラインが無事成功し、該当AWSアカウントのVPCコンソールを確認すると、以下の通りVPCおよび各サブネットが作成されていることが確認できました。
検証は以上です。
終わりに
cutom_fields
を活用することによって、AWSアカウント固有のパラメータを中央管理的に管理・配布し、各メンバーアカウントでは共通テンプレート化されたTerraformコードを実行することが可能です。今回はその方法でVPCリソース一式をモジュールを使い作成しました。
この方法であれば、AFTのグローバル/アカウントのカスタマイズをより柔軟に行えることがわかりました。積極的に使っていきたいと思います。
それではこの辺で。ちゃだいん(@chazuke4649)でした。